`timescale 1ns/1ps
`default_nettype none

module serial_divider
#(parameter
    M    = 8,  //width of numerator
    N    = 8,  //width of denominator
    MODE = 0   //0 - unsigned, 1 - signed
)
(
    //system singal
    input  wire         I_sclk,
    input  wire         I_rst_n,
    //divide
    input  wire         I_start,
    input  wire [M-1:0] I_numer,
    input  wire [N-1:0] I_denom,
    output wire         O_done,
    output wire [M-1:0] O_quotient,
    output wire [N-1:0] O_remain
);
//------------------------Parameter----------------------

//------------------------Local signal-------------------
reg           sign0; // sign of numerator
reg           sign1; // sign of denominator
reg [M+N-1:0] sr;    // shift register
reg [N-1:0]   dn;    // denominator
reg [7:0]     i;     // counter
reg           busy;
reg           over;

//------------------------Instantiation------------------

//------------------------Body---------------------------
assign O_done     = over;
assign O_quotient = (sign0^sign1)? ~sr[M-1:0] + 1'b1 : sr[M-1:0];
assign O_remain   = sign0? ~sr[M+N-1:M] + 1'b1 : sr[M+N-1:M];

//sign0,sign1
always @(posedge I_sclk or negedge I_rst_n) begin
    if(!I_rst_n) begin
        sign0 <= 1'b0;
        sign1 <= 1'b0;
    end
    else if(I_start) begin
        sign0 <= MODE? I_numer[M-1] : 1'b0;
        sign1 <= MODE? I_denom[N-1] : 1'b0;
    end
end

//sr
always @(posedge I_sclk or negedge I_rst_n) begin
    if(!I_rst_n)
        sr <= 1'b0;
    else if(I_start) begin
        if(MODE & I_numer[M-1])
            sr <= {{N{1'b0}},~I_numer + 1'b1};
        else
            sr <= {{N{1'b0}},I_numer};
    end
    else if(busy) begin
        if(sr[M+N-1:M-1]>=dn)
            sr <= {sr[M+N-2:M-1]-dn,sr[M-2:0],1'b1};
        else
            sr <= {sr[M+N-2:0],1'b0};
    end
end

//dn
always @(posedge I_sclk or negedge I_rst_n) begin
    if(!I_rst_n)
        dn <= 1'b1;
    else if(I_start) begin
        if(MODE & I_denom[N-1])
            dn <= ~I_denom + 1'b1;
        else
            dn <= I_denom;
    end
end

//i
always @(posedge I_sclk or negedge I_rst_n) begin
    if(!I_rst_n)
        i <= 1'b1;
    else if(~busy)
        i <= 1'b1;
    else
        i <= i + 1'b1;
end

//busy
always @(posedge I_sclk or negedge I_rst_n) begin
    if(!I_rst_n)
        busy <= 1'b0;
    else if(I_start)
        busy <= 1'b1;
    else if(i==M)
        busy <= 1'b0;
end

//over
always @(posedge I_sclk or negedge I_rst_n) begin
    if(!I_rst_n)
        over <= 1'b0;
    else if(i==M)
        over <= 1'b1;
    else
        over <= 1'b0;
end

endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
